home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / gfx / misc / gnuplot-src.lha / gnuplot-3.7.1src / gnuplot-3.7.1.lha / gnuplot-3.7.1 / util3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-22  |  31.8 KB  |  1,261 lines

  1. #ifndef lintiz == oz}
  2.   
  3.    Sid = "$Id: util3d.c,v 1.7 1998/09/21 21:04:42 lhecking Exp $";
  4. #endif
  5.  
  6.  
  7. /* GNUPLOT - util3d.c */
  8.  
  9. /*[
  10.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  11.  *
  12.  * Permission to use, copy, and distribute this software and its
  13.  * documentation for any purpose with or without fee is hereby granted,
  14.  * provided that the above copyright notice appear in all copies and
  15.  * that both that copyright notice and this permission notice appear
  16.  * in supporting documentation.
  17.  *
  18.  * Permission to modify the software is granted, but not the right to
  19.  * distribute the complete modified source code.  Modifications are to
  20.  * be distributed as patches to the released version.  Permission to
  21.  * distribute binaries produced by compiling modified sources is granted,
  22.  * provided you
  23.  *   1. distribute the corresponding source modifications from the
  24.  *    released version in the form of a patch file along with the binaries,
  25.  *   2. add special version identification to distinguish your version
  26.  *    in addition to the base release version number,
  27.  *   3. provide your name and address as the primary contact for the
  28.  *    support of your modified version, and
  29.  *   4. retain our contact information in regard to use of the base
  30.  *    software.
  31.  * Permission to distribute the released version of the source code along
  32.  * with corresponding source modifications in the form of a patch file is
  33.  * granted with same provisions 2 through 4 for binary distributions.
  34.  *
  35.  * This software is provided "as is" without express or implied warranty
  36.  * to the extent permitted by applicable law.
  37. ]*/
  38.  
  39.  
  40. /*
  41.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  42.  * Added user-specified bases for log scaling.
  43.  *
  44.  * 3.6 - split graph3d.c into graph3d.c (graph),
  45.  *                            util3d.c (intersections, etc)
  46.  *                            hidden3d.c (hidden-line removal code)
  47.  *
  48.  */
  49.  
  50. #include "plot.h"
  51. #include "setshow.h"
  52.  
  53. extern int xleft,xright,ybot,ytop;
  54. extern int hidden_active; /* HBB 980324: hidden_no_update was unused here */
  55.  
  56. /* ACCESS THINGS THAT OUGHT TO BE HIDDEN IN hidden3d.c - perhaps we
  57.  * can move the relevant code into hidden3d.c sometime
  58.  */
  59.  
  60. /* Bitmap of the screen.  The array for each x value is malloc-ed as needed */
  61.  
  62. extern int suppressMove;
  63.  
  64. extern double min_array[], max_array[];
  65. extern int auto_array[], log_array[];
  66. extern double base_array[], log_base_array[];
  67.  
  68. /* for convenience while converting to use these arrays */
  69. #define x_min3d min_array[FIRST_X_AXIS]
  70. #define x_max3d max_array[FIRST_X_AXIS]
  71. #define y_min3d min_array[FIRST_Y_AXIS]
  72. #define y_max3d max_array[FIRST_Y_AXIS]
  73. #define z_min3d min_array[FIRST_Z_AXIS]
  74. #define z_max3d max_array[FIRST_Z_AXIS]
  75. #define min3d_z min_array[FIRST_Z_AXIS]
  76. #define max3d_z max_array[FIRST_Z_AXIS]
  77.  
  78. typedef double transform_matrix[4][4];
  79.  
  80. void mat_unit(mat)
  81. transform_matrix mat;
  82. {
  83.     int i, j;
  84.  
  85.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
  86.     if (i == j)
  87.         mat[i][j] = 1.0;
  88.     else
  89.         mat[i][j] = 0.0;
  90. }
  91.  
  92. void mat_trans(tx, ty, tz, mat)
  93. double tx, ty, tz;
  94. transform_matrix mat;
  95. {
  96.      mat_unit(mat);                                 /* Make it unit matrix. */
  97.      mat[3][0] = tx;
  98.      mat[3][1] = ty;
  99.      mat[3][2] = tz;
  100. }
  101.  
  102. void mat_scale(sx, sy, sz, mat)
  103. double sx, sy, sz;
  104. transform_matrix mat;
  105. {
  106.      mat_unit(mat);                                 /* Make it unit matrix. */
  107.      mat[0][0] = sx;
  108.      mat[1][1] = sy;
  109.      mat[2][2] = sz;
  110. }
  111.  
  112. void mat_rot_x(teta, mat)
  113. double teta;
  114. transform_matrix mat;
  115. {
  116.     double cos_teta, sin_teta;
  117.  
  118.     teta *= Pi / 180.0;
  119.     cos_teta = cos(teta);
  120.     sin_teta = sin(teta);
  121.  
  122.     mat_unit(mat);                                  /* Make it unit matrix. */
  123.     mat[1][1] = cos_teta;
  124.     mat[1][2] = -sin_teta;
  125.     mat[2][1] = sin_teta;
  126.     mat[2][2] = cos_teta;
  127. }
  128.  
  129. void mat_rot_y(teta, mat)
  130. double teta;
  131. transform_matrix mat;
  132. {
  133.     double cos_teta, sin_teta;
  134.  
  135.     teta *= Pi / 180.0;
  136.     cos_teta = cos(teta);
  137.     sin_teta = sin(teta);
  138.  
  139.     mat_unit(mat);                                  /* Make it unit matrix. */
  140.     mat[0][0] = cos_teta;
  141.     mat[0][2] = -sin_teta;
  142.     mat[2][0] = sin_teta;
  143.     mat[2][2] = cos_teta;
  144. }
  145.  
  146. void mat_rot_z(teta, mat)
  147. double teta;
  148. transform_matrix mat;
  149. {
  150.     double cos_teta, sin_teta;
  151.  
  152.     teta *= Pi / 180.0;
  153.     cos_teta = cos(teta);
  154.     sin_teta = sin(teta);
  155.  
  156.     mat_unit(mat);                                  /* Make it unit matrix. */
  157.     mat[0][0] = cos_teta;
  158.     mat[0][1] = -sin_teta;
  159.     mat[1][0] = sin_teta;
  160.     mat[1][1] = cos_teta;
  161. }
  162.  
  163. /* Multiply two transform_matrix. Result can be one of two operands. */
  164. void mat_mult(mat_res, mat1, mat2)
  165. transform_matrix mat_res, mat1, mat2;
  166. {
  167.     int i, j, k;
  168.     transform_matrix mat_res_temp;
  169.  
  170.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) {
  171.         mat_res_temp[i][j] = 0;
  172.         for (k = 0; k < 4; k++) mat_res_temp[i][j] += mat1[i][k] * mat2[k][j];
  173.     }
  174.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
  175.     mat_res[i][j] = mat_res_temp[i][j];
  176. }
  177.  
  178.  
  179. /* Test a single point to be within the xleft,xright,ybot,ytop bbox.
  180.  * Sets the returned integers 4 l.s.b. as follows:
  181.  * bit 0 if to the left of xleft.
  182.  * bit 1 if to the right of xright.
  183.  * bit 2 if above of ytop.
  184.  * bit 3 if below of ybot.
  185.  * 0 is returned if inside.
  186.  */
  187. int clip_point(x, y)
  188. unsigned int x, y;
  189. {
  190.     int ret_val = 0;
  191.  
  192.     if (x < xleft) ret_val |= 0x01;
  193.     if (x > xright) ret_val |= 0x02;
  194.     if (y < ybot) ret_val |= 0x04;
  195.     if (y > ytop) ret_val |= 0x08;
  196.  
  197.     return ret_val;
  198. }
  199.  
  200. /* Clip the given line to drawing coords defined as xleft,xright,ybot,ytop.
  201.  *   This routine uses the cohen & sutherland bit mapping for fast clipping -
  202.  * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
  203.  */
  204. void draw_clip_line(x1, y1, x2, y2)
  205. unsigned int x1, y1, x2, y2;
  206. {
  207.     int x, y, dx, dy, x_intr[4], y_intr[4], count, pos1, pos2;
  208.     register struct termentry *t = term;
  209.  
  210. #if defined(ATARI) || defined(MTOS)
  211.     if(x1<0||x2<0||y1<0||y2<0) return; /* temp bug fix */
  212. #endif
  213.  
  214.     pos1 = clip_point(x1, y1);
  215.     pos2 = clip_point(x2, y2);
  216.     if (pos1 || pos2) {
  217.     if (pos1 & pos2) return;         /* segment is totally out. */
  218.  
  219.     /* Here part of the segment MAY be inside. test the intersection
  220.      * of this segment with the 4 boundaries for hopefully 2 intersections
  221.      * in. If none are found segment is totaly out.
  222.      * Under rare circumstances there may be up to 4 intersections (e.g.
  223.      * when the line passes directly through at least one corner). In
  224.      * this case it is sufficient to take any 2 intersections (e.g. the
  225.      * first two found).
  226.      */
  227.     count = 0;
  228.     dx = x2 - x1;
  229.     dy = y2 - y1;
  230.  
  231.     /* Find intersections with the x parallel bbox lines: */
  232.     if (dy != 0) {
  233.         x = (ybot - y2) * dx / dy + x2;      /* Test for ybot boundary. */
  234.         if (x >= xleft && x <= xright) {
  235.         x_intr[count] = x;
  236.         y_intr[count++] = ybot;
  237.         }
  238.         x = (ytop - y2) * dx / dy + x2;      /* Test for ytop boundary. */
  239.         if (x >= xleft && x <= xright) {
  240.         x_intr[count] = x;
  241.         y_intr[count++] = ytop;
  242.         }
  243.     }
  244.  
  245.     /* Find intersections with the y parallel bbox lines: */
  246.     if (dx != 0) {
  247.         y = (xleft - x2) * dy / dx + y2;    /* Test for xleft boundary. */
  248.         if (y >= ybot && y <= ytop) {
  249.         x_intr[count] = xleft;
  250.         y_intr[count++] = y;
  251.         }
  252.         y = (xright - x2) * dy / dx + y2;  /* Test for xright boundary. */
  253.         if (y >= ybot && y <= ytop) {
  254.         x_intr[count] = xright;
  255.         y_intr[count++] = y;
  256.         }
  257.     }
  258.  
  259.     if (count >= 2) {
  260.         int x_max, x_min, y_max, y_min;
  261.  
  262.         x_min = GPMIN(x1, x2);
  263.         x_max = GPMAX(x1, x2);
  264.         y_min = GPMIN(y1, y2);
  265.         y_max = GPMAX(y1, y2);
  266.  
  267.         if (pos1 && pos2) {              /* Both were out - update both */
  268.         x1 = x_intr[0];
  269.         y1 = y_intr[0];
  270.         x2 = x_intr[1];
  271.         y2 = y_intr[1];
  272.         }
  273.         else if (pos1) {         /* Only x1/y1 was out - update only it */
  274.         if (dx * (x2 - x_intr[0]) + dy * (y2 - y_intr[0]) > 0) {
  275.             x1 = x_intr[0];
  276.             y1 = y_intr[0];
  277.         }
  278.         else {
  279.             x1 = x_intr[1];
  280.             y1 = y_intr[1];
  281.         }
  282.         }
  283.         else {                    /* Only x2/y2 was out - update only it */
  284.         if (dx * (x_intr[0] - x1) + dy * (y_intr[0] - y1) > 0) {
  285.             x2 = x_intr[0];
  286.             y2 = y_intr[0];
  287.         }
  288.         else {
  289.             x2 = x_intr[1];
  290.             y2 = y_intr[1];
  291.         }
  292.         }
  293.  
  294.         if (x1 < x_min || x1 > x_max ||
  295.         x2 < x_min || x2 > x_max ||
  296.         y1 < y_min || y1 > y_max ||
  297.         y2 < y_min || y2 > y_max) return;
  298.     }
  299.     else
  300.         return;
  301.     }
  302.  
  303.     
  304. #ifndef LITE
  305.     if(hidden3d && hidden_active && draw_surface)
  306.       {
  307.         draw_line_hidden(x1, y1, x2, y2);
  308.         return;
  309.       };
  310. #endif /* not LITE */
  311.     if(!suppressMove) (*t->move)(x1,y1);
  312.     (*t->vector)(x2,y2);
  313. }
  314.  
  315.  
  316.  
  317. /* And text clipping routine. */
  318. void clip_put_text(x, y, str)
  319. unsigned int x,y;
  320. char *str;
  321. {
  322.     register struct termentry *t = term;
  323.  
  324.     if (clip_point(x, y)) return;
  325.  
  326.     (*t->put_text)(x,y,str);
  327. }
  328.  
  329. /* seems sensible to put the justification in here too..? */
  330. void clip_put_text_just(x,y,str,just)
  331. unsigned int x,y;
  332. char *str;
  333. enum JUSTIFY just;
  334. {
  335.         register struct termentry *t = term;
  336.     if (clip_point(x,y)) return;
  337.     if (!(*t->justify_text)(just)) {
  338.         assert(CENTRE == 1 && RIGHT == 2);
  339.         x -= (t->h_char * strlen(str) * just)/2;
  340.     }
  341.     (*t->put_text)(x,y,str);
  342. }
  343.  
  344.  
  345.  
  346. /* Clip the given line to drawing coords defined as xleft,xright,ybot,ytop.
  347.  *   This routine uses the cohen & sutherland bit mapping for fast clipping -
  348.  * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
  349.  */
  350.  
  351. int clip_line(x1, y1, x2, y2)
  352.      int *x1, *y1, *x2, *y2;
  353. {
  354.   int x, y, dx, dy, x_intr[4], y_intr[4], count, pos1, pos2;
  355.   int x_max, x_min, y_max, y_min;
  356.   pos1 = clip_point(*x1, *y1);
  357.   pos2 = clip_point(*x2, *y2);
  358.   if (!pos1 && !pos2) return 1; /* segment is totally in */ 
  359.   if (pos1 & pos2) return 0;    /* segment is totally out. */ 
  360.   /* Here part of the segment MAY be inside. test the intersection
  361.    * of this segment with the 4 boundaries for hopefully 2 intersections
  362.    * in. If non found segment is totaly out.
  363.    */ 
  364.   count = 0;
  365.   dx = *x2 - *x1;  
  366.   dy = *y2 - *y1;
  367.   /* Find intersections with the x parallel bbox lines: */ 
  368.   if (dy != 0) {
  369.     x = (ybot - *y2) * dx / dy + *x2; /* Test for ybot boundary. */ 
  370.     if (x >= xleft && x <= xright) {
  371.       x_intr[count] = x;       
  372.       y_intr[count++] = ybot;
  373.     }
  374.     x = (ytop - *y2) * dx / dy + *x2; /* Test for ytop boundary. */ 
  375.     if (x >= xleft && x <= xright) {
  376.       x_intr[count] = x;       
  377.       y_intr[count++] = ytop;
  378.     }
  379.   }
  380.   /* Find intersections with the y parallel bbox lines: */ 
  381.   if (dx != 0) {
  382.     y = (xleft - *x2) * dy / dx + *y2; /* Test for xleft boundary. */
  383.     if (y >= ybot && y <= ytop) {
  384.       x_intr[count] = xleft;   
  385.       y_intr[count++] = y;
  386.     }
  387.     y = (xright - *x2) * dy / dx + *y2; /* Test for xright boundary. */
  388.     if (y >= ybot && y <= ytop) {
  389.       x_intr[count] = xright;  
  390.       y_intr[count++] = y;
  391.     }
  392.   }
  393.   if (count < 2) return 0;
  394.   if (*x1 < *x2)
  395.     x_min = *x1, x_max = *x2;
  396.   else
  397.     x_min = *x2, x_max = *x1;
  398.   if (*y1 < *y2)
  399.     y_min = *y1, y_max = *y2;
  400.   else
  401.     y_min = *y2, y_max = *y1;
  402.   if (pos1 && pos2) {        /* Both were out - update both */
  403.     *x1 = x_intr[0];     
  404.     *y1 = y_intr[0];
  405.     *x2 = x_intr[1];     
  406.     *y2 = y_intr[1];
  407.   }
  408.   else if (pos1) 
  409.     {                /* Only x1/y1 was out - update only it */
  410.       if (dx * (*x2 - x_intr[0]) + dy * (*y2 - y_intr[0]) >= 0) 
  411.     {    
  412.       *x1 = x_intr[0];   
  413.       *y1 = y_intr[0];  
  414.     }
  415.       else 
  416.     { 
  417.       *x1 = x_intr[1];   
  418.       *y1 = y_intr[1];  
  419.     }
  420.     }
  421.   else 
  422.     {                /* Only x2/y2 was out - update only it */
  423.       if (dx * (x_intr[0] - *x1) + dy * (y_intr[0] - *y1) >= 0) 
  424.     {    
  425.       *x2 = x_intr[0];   
  426.       *y2 = y_intr[0];  
  427.     }
  428.       else 
  429.     { 
  430.       *x2 = x_intr[1];   
  431.       *y2 = y_intr[1];  
  432.     }
  433.     }
  434.  
  435.   if (*x1 < x_min || *x1 > x_max ||  
  436.       *x2 < x_min || *x2 > x_max ||
  437.       *y1 < y_min || *y1 > y_max ||  
  438.       *y2 < y_min || *y2 > y_max) 
  439.     return 0;
  440.   return 1;
  441. }
  442.  
  443.  
  444. /* single edge intersection algorithm */
  445. /* Given two points, one inside and one outside the plot, return
  446.  * the point where an edge of the plot intersects the line segment defined 
  447.  * by the two points.
  448.  */
  449. void edge3d_intersect(points, i, ex, ey, ez)
  450.     struct coordinate GPHUGE *points; /* the points array */
  451.     int i;                /* line segment from point i-1 to point i */
  452.     double *ex, *ey, *ez;        /* the point where it crosses an edge */
  453. {
  454.     /* global x_min3d, x_max3d, y_min3d, y_max3d, min3d_z, max3d_z */
  455.     int count;
  456.     double ix = points[i-1].x;
  457.     double iy = points[i-1].y;
  458.     double iz = points[i-1].z;
  459.     double ox = points[i].x;
  460.     double oy = points[i].y;
  461.     double oz = points[i].z;
  462.     double x, y, z;            /* possible intersection point */
  463.  
  464.     if(points[i].type == INRANGE)
  465.       {
  466.     /* swap points around so that ix/ix/iz are INRANGE and ox/oy/oz are OUTRANGE */
  467.     x = ix;ix = ox;ox = x;
  468.     y = iy;iy = oy;oy = y;
  469.     z = iz;iz = oz;oz = z;
  470.       }
  471.  
  472.     /* nasty degenerate cases, effectively drawing to an infinity point (?)
  473.        cope with them here, so don't process them as a "real" OUTRANGE point 
  474.  
  475.        If more than one coord is -VERYLARGE, then can't ratio the "infinities"
  476.        so drop out by returning the INRANGE point.
  477.  
  478.        Obviously, only need to test the OUTRANGE point (coordinates) */
  479.  
  480.     /* nasty degenerate cases, effectively drawing to an infinity point (?)
  481.        cope with them here, so don't process them as a "real" OUTRANGE point 
  482.  
  483.        If more than one coord is -VERYLARGE, then can't ratio the "infinities"
  484.        so drop out by returning FALSE */
  485.     
  486.     count = 0;
  487.     if(ox == -VERYLARGE) count++;
  488.     if(oy == -VERYLARGE) count++;
  489.     if(oz == -VERYLARGE) count++;
  490.  
  491.     /* either doesn't pass through 3D volume *or* 
  492.        can't ratio infinities to get a direction to draw line, so return the INRANGE point */
  493.     if(count > 1){
  494.       *ex = ix;
  495.       *ey = iy;
  496.       *ez = iz;
  497.  
  498.       return;
  499.     }
  500.  
  501.     if(count == 1)
  502.       {
  503.     *ex = ix;
  504.     *ey = iy;
  505.     *ez = iz;
  506.  
  507.     if(ox == -VERYLARGE)
  508.       {
  509.         *ex = x_min3d;
  510.         return;
  511.       }
  512.  
  513.     if(oy == -VERYLARGE)
  514.       {
  515.         *ey = y_min3d;
  516.         return;
  517.       }
  518.  
  519.     /* obviously oz is -VERYLARGE and (ox != -VERYLARGE && oy != -VERYLARGE) */
  520.     *ez = min3d_z;
  521.     return;
  522.       }
  523.  
  524.     /*
  525.      * Can't have case (ix == ox && iy == oy && iz == oz) as one point
  526.      * is INRANGE and one point is OUTRANGE.
  527.      */
  528.     if(ix == ox) {
  529.       if(iy == oy) {
  530.     /* line parallel to z axis */
  531.  
  532.     /* assume inrange(iy, y_min3d, y_max3d) && inrange(ix, x_min3d, x_max3d) */
  533.     *ex = ix;        /* == ox */
  534.     *ey = iy;        /* == oy */
  535.     
  536.     if (inrange(max3d_z, iz, oz))
  537.       *ez = max3d_z;
  538.     else if (inrange(min3d_z, iz, oz))
  539.       *ez = min3d_z;
  540.     else {
  541.       graph_error("error in edge3d_intersect");
  542.         }
  543.  
  544.     return;
  545.       }
  546.       
  547.       if(iz == oz) {
  548.     /* line parallel to y axis */
  549.     
  550.     /* assume inrange(iz, min3d_z, max3d_z) && inrange(ix, x_min3d, x_max3d) */
  551.     *ex = ix;        /* == ox */
  552.     *ez = iz;        /* == oz */
  553.     
  554.     if (inrange(y_max3d, iy, oy))
  555.       *ey = y_max3d;
  556.     else if (inrange(y_min3d, iy, oy))
  557.       *ey = y_min3d;
  558.     else {
  559.       graph_error("error in edge3d_intersect");
  560.     }
  561.     
  562.     return;
  563.       }
  564.  
  565.       /* nasty 2D slanted line in a yz plane */
  566.       
  567.       /* does it intersect y_min3d edge */
  568.       if (inrange(y_min3d, iy, oy) && y_min3d != iy && y_min3d != oy) {
  569.     z = iz + (y_min3d-iy) * ((oz-iz) / (oy-iy));
  570.     if (inrange(z, min3d_z, max3d_z)) {
  571.       *ex = ix;
  572.       *ey = y_min3d;
  573.       *ez = z;
  574.       return;
  575.     }
  576.       }
  577.  
  578.       /* does it intersect y_max3d edge */
  579.       if (inrange(y_max3d, iy, oy) && y_max3d != iy && y_max3d != oy) {
  580.     z = iz + (y_max3d-iy) * ((oz-iz) / (oy-iy));
  581.     if (inrange(z, min3d_z, max3d_z)) {
  582.       *ex = ix;
  583.       *ey = y_max3d;
  584.       *ez = z;
  585.       return;
  586.     }
  587.       }
  588.  
  589.       /* does it intersect min3d_z edge */
  590.       if (inrange(min3d_z, iz, oz) && min3d_z != iz && min3d_z != oz) {
  591.     y = iy + (min3d_z-iz) * ((oy-iy) / (oz-iz));
  592.     if (inrange(y, y_min3d, y_max3d)) {
  593.       *ex = ix;
  594.       *ey = y;
  595.       *ez = min3d_z;
  596.       return;
  597.     }
  598.       }
  599.  
  600.       /* does it intersect max3d_z edge */
  601.       if (inrange(max3d_z, iz, oz) && max3d_z != iz && max3d_z != oz) {
  602.     y = iy + (max3d_z-iz) * ((oy-iy) / (oz-iz));
  603.     if (inrange(y, y_min3d, y_max3d)) {
  604.       *ex = ix;
  605.       *ey = y;
  606.       *ez = max3d_z;
  607.       return;
  608.     }
  609.       }
  610.     }
  611.       
  612.     if(iy == oy) {
  613.       /* already checked case (ix == ox && iy == oy) */
  614.       if(oz ==  iz) {
  615.       /* line parallel to x axis */
  616.  
  617.       /* assume inrange(iz, min3d_z, max3d_z) && inrange(iy, y_min3d, y_max3d) */
  618.       *ey = iy;        /* == oy */
  619.       *ez = iz;        /* == oz */
  620.       
  621.       if (inrange(x_max3d, ix, ox))
  622.         *ex = x_max3d;
  623.       else if (inrange(x_min3d, ix, ox))
  624.         *ex = x_min3d;
  625.       else {
  626.         graph_error("error in edge3d_intersect");
  627.       }
  628.  
  629.       return;
  630.       }
  631.  
  632.       /* nasty 2D slanted line in an xz plane */
  633.  
  634.       /* does it intersect x_min3d edge */
  635.       if (inrange(x_min3d, ix, ox) && x_min3d != ix && x_min3d != ox) {
  636.     z = iz + (x_min3d-ix) * ((oz-iz) / (ox-ix));
  637.     if (inrange(z, min3d_z, max3d_z)) {
  638.       *ex = x_min3d;
  639.       *ey = iy;
  640.       *ez = z;
  641.       return;
  642.     }
  643.       }
  644.  
  645.       /* does it intersect x_max3d edge */
  646.       if (inrange(x_max3d, ix, ox) && x_max3d != ix && x_max3d != ox) {
  647.     z = iz + (x_max3d-ix) * ((oz-iz) / (ox-ix));
  648.     if (inrange(z, min3d_z, max3d_z)) {
  649.       *ex = x_max3d;
  650.       *ey = iy;
  651.       *ez = z;
  652.       return;
  653.     }
  654.       }
  655.  
  656.       /* does it intersect min3d_z edge */
  657.       if (inrange(min3d_z, iz, oz) && min3d_z != iz && min3d_z != oz) {
  658.     x = ix + (min3d_z-iz) * ((ox-ix) / (oz-iz));
  659.     if (inrange(x, x_min3d, x_max3d)) {
  660.       *ex = x;
  661.       *ey = iy;
  662.       *ez = min3d_z;
  663.       return;
  664.     }
  665.       }
  666.       
  667.       /* does it intersect max3d_z edge */
  668.       if (inrange(max3d_z, iz, oz) && max3d_z != iz && max3d_z != oz) {
  669.     x = ix + (max3d_z-iz) * ((ox-ix) / (oz-iz));
  670.     if (inrange(x, x_min3d, x_max3d)) {
  671.       *ex = x;
  672.       *ey = iy;
  673.       *ez = max3d_z;
  674.       return;
  675.     }
  676.       }      
  677.     }
  678.     
  679.     if(iz == oz) {
  680.       /* already checked cases (ix == ox && iz == oz) and (iy == oy && iz == oz) */
  681.  
  682.       /* nasty 2D slanted line in an xy plane */
  683.  
  684.       /* assume inrange(oz, min3d_z, max3d_z) */
  685.  
  686.       /* does it intersect x_min3d edge */
  687.       if (inrange(x_min3d, ix, ox) && x_min3d != ix && x_min3d != ox) {
  688.     y = iy + (x_min3d-ix) * ((oy-iy) / (ox-ix));
  689.     if (inrange(y, y_min3d, y_max3d)) {
  690.       *ex = x_min3d;
  691.       *ey = y;
  692.       *ez = iz;
  693.       return;
  694.     }
  695.       }
  696.  
  697.       /* does it intersect x_max3d edge */
  698.       if (inrange(x_max3d, ix, ox) && x_max3d != ix && x_max3d != ox) {
  699.     y = iy + (x_max3d-ix) * ((oy-iy) / (ox-ix));
  700.     if (inrange(y, y_min3d, y_max3d)) {
  701.       *ex = x_max3d;
  702.       *ey = y;
  703.       *ez = iz;
  704.       return;
  705.     }
  706.       }    
  707.       
  708.       /* does it intersect y_min3d edge */
  709.       if (inrange(y_min3d, iy, oy) && y_min3d != iy && y_min3d != oy) {
  710.     x = ix + (y_min3d-iy) * ((ox-ix) / (oy-iy));
  711.     if (inrange(x, x_min3d, x_max3d)) {
  712.       *ex = x;
  713.       *ey = y_min3d;
  714.       *ez = iz;
  715.       return;
  716.     }
  717.       }
  718.       
  719.       /* does it intersect y_max3d edge */
  720.       if (inrange(y_max3d, iy, oy) && y_max3d != iy && y_max3d != oy) {
  721.     x = ix + (y_max3d-iy) * ((ox-ix) / (oy-iy));
  722.     if (inrange(x, x_min3d, x_max3d)) {
  723.       *ex = x;
  724.       *ey = y_max3d;
  725.       *ez = iz;
  726.       return;
  727.     }
  728.       }
  729.     }
  730.   
  731.     /* really nasty general slanted 3D case */
  732.  
  733.     /* does it intersect x_min3d edge */
  734.     if (inrange(x_min3d, ix, ox) && x_min3d != ix && x_min3d != ox) {
  735.       y = iy + (x_min3d-ix) * ((oy-iy) / (ox-ix));
  736.       z = iz + (x_min3d-ix) * ((oz-iz) / (ox-ix));
  737.       if (inrange(y, y_min3d, y_max3d) && inrange(z, min3d_z, max3d_z)) {
  738.     *ex = x_min3d;
  739.     *ey = y;
  740.     *ez = z;
  741.     return;
  742.       }
  743.     }
  744.  
  745.     /* does it intersect x_max3d edge */
  746.     if (inrange(x_max3d, ix, ox) && x_max3d != ix && x_max3d != ox) {
  747.       y = iy + (x_max3d-ix) * ((oy-iy) / (ox-ix));
  748.       z = iz + (x_max3d-ix) * ((oz-iz) / (ox-ix));
  749.       if (inrange(y, y_min3d, y_max3d) && inrange(z, min3d_z, max3d_z)) {
  750.     *ex = x_max3d;
  751.     *ey = y;
  752.     *ez = z;
  753.     return;
  754.       }
  755.     }
  756.  
  757.     /* does it intersect y_min3d edge */
  758.     if (inrange(y_min3d, iy, oy) && y_min3d != iy && y_min3d != oy) {
  759.       x = ix + (y_min3d-iy) * ((ox-ix) / (oy-iy));
  760.       z = iz + (y_min3d-iy) * ((oz-iz) / (oy-iy));
  761.       if (inrange(x, x_min3d, x_max3d) && inrange(z, min3d_z, max3d_z)) {
  762.     *ex = x;
  763.     *ey = y_min3d;
  764.     *ez = z;
  765.     return;
  766.       }
  767.     }
  768.  
  769.     /* does it intersect y_max3d edge */
  770.     if (inrange(y_max3d, iy, oy) && y_max3d != iy && y_max3d != oy) {
  771.       x = ix + (y_max3d-iy) * ((ox-ix) / (oy-iy));
  772.       z = iz + (y_max3d-iy) * ((oz-iz) / (oy-iy));
  773.       if (inrange(x, x_min3d, x_max3d) && inrange(z, min3d_z, max3d_z)) {
  774.     *ex = x;
  775.     *ey = y_max3d;
  776.     *ez = z;
  777.     return;
  778.       }
  779.     }
  780.  
  781.     /* does it intersect min3d_z edge */
  782.     if (inrange(min3d_z, iz, oz) && min3d_z != iz && min3d_z != oz) {
  783.       x = ix + (min3d_z-iz) * ((ox-ix) / (oz-iz));
  784.       y = iy + (min3d_z-iz) * ((oy-iy) / (oz-iz));
  785.       if (inrange(x, x_min3d, x_max3d) && inrange(y, y_min3d, y_max3d)) {
  786.     *ex = x;
  787.     *ey = y;
  788.     *ez = min3d_z;
  789.     return;
  790.       }
  791.     }
  792.  
  793.     /* does it intersect max3d_z edge */
  794.     if (inrange(max3d_z, iz, oz) && max3d_z != iz && max3d_z != oz) {
  795.       x = ix + (max3d_z-iz) * ((ox-ix) / (oz-iz));
  796.       y = iy + (max3d_z-iz) * ((oy-iy) / (oz-iz));
  797.       if (inrange(x, x_min3d, x_max3d) && inrange(y, y_min3d, y_max3d)) {
  798.     *ex = x;
  799.     *ey = y;
  800.     *ez = max3d_z;
  801.     return;
  802.       }
  803.     }
  804.  
  805.     /* If we reach here, the inrange point is on the edge, and
  806.      * the line segment from the outrange point does not cross any 
  807.      * other edges to get there. In this case, we return the inrange 
  808.      * point as the 'edge' intersection point. This will basically draw
  809.      * line.
  810.      */
  811.     *ex = ix;
  812.     *ey = iy;
  813.     *ez = iz;
  814.     return;
  815. }
  816.  
  817. /* double edge intersection algorithm */
  818. /* Given two points, both outside the plot, return
  819.  * the points where an edge of the plot intersects the line segment defined 
  820.  * by the two points. There may be zero, one, two, or an infinite number
  821.  * of intersection points. (One means an intersection at a corner, infinite
  822.  * means overlaying the edge itself). We return FALSE when there is nothing
  823.  * to draw (zero intersections), and TRUE when there is something to 
  824.  * draw (the one-point case is a degenerate of the two-point case and we do 
  825.  * not distinguish it - we draw it anyway).
  826.  */
  827. TBOOLEAN                                /* any intersection? */
  828. two_edge3d_intersect(points, i, lx, ly, lz)
  829.     struct coordinate GPHUGE *points; /* the points array */
  830.     int i;                /* line segment from point i-1 to point i */
  831.     double *lx, *ly, *lz;        /* lx[2], ly[2], lz[2]: points where it crosses edges */
  832. {
  833.     int count;
  834.     /* global x_min3d, x_max3d, y_min3d, y_max3d, min3d_z, max3d_z */
  835.     double ix = points[i-1].x;
  836.     double iy = points[i-1].y;
  837.     double iz = points[i-1].z;
  838.     double ox = points[i].x;
  839.     double oy = points[i].y;
  840.     double oz = points[i].z;
  841.     double t[6];
  842.     double swap;
  843.     double x, y, z;            /* possible intersection point */
  844.     double t_min, t_max;
  845.  
  846.     /* nasty degenerate cases, effectively drawing to an infinity point (?)
  847.        cope with them here, so don't process them as a "real" OUTRANGE point 
  848.  
  849.        If more than one coord is -VERYLARGE, then can't ratio the "infinities"
  850.        so drop out by returning FALSE */
  851.     
  852.     count = 0;
  853.     if(ix == -VERYLARGE) count++;
  854.     if(ox == -VERYLARGE) count++;
  855.     if(iy == -VERYLARGE) count++;
  856.     if(oy == -VERYLARGE) count++;
  857.     if(iz == -VERYLARGE) count++;
  858.     if(oz == -VERYLARGE) count++;
  859.  
  860.     /* either doesn't pass through 3D volume *or* 
  861.        can't ratio infinities to get a direction to draw line, so simply return(FALSE) */
  862.     if(count > 1){
  863.       return(FALSE);
  864.     }
  865.  
  866.     if(ox == -VERYLARGE || ix == -VERYLARGE)
  867.       {
  868.     if(ix == -VERYLARGE)
  869.       {
  870.         /* swap points so ix/iy/iz don't have a -VERYLARGE component */
  871.         x = ix;ix = ox;ox = x;
  872.         y = iy;iy = oy;oy = y;
  873.         z = iz;iz = oz;oz = z;
  874.       }
  875.  
  876.     /* check actually passes through the 3D graph volume */
  877.     if(ix > x_max3d && inrange(iy, y_min3d, y_max3d) && inrange(iz, min3d_z, max3d_z))
  878.       {
  879.         lx[0] = x_min3d;
  880.         ly[0] = iy;
  881.         lz[0] = iz;
  882.  
  883.         lx[1] = x_max3d;
  884.         ly[1] = iy;
  885.         lz[1] = iz;
  886.  
  887.         return(TRUE);
  888.       }
  889.     else {
  890.       return(FALSE);
  891.     }
  892.       }
  893.  
  894.     if(oy == -VERYLARGE || iy == -VERYLARGE)
  895.       {
  896.     if(iy == -VERYLARGE)
  897.       {
  898.         /* swap points so ix/iy/iz don't have a -VERYLARGE component */
  899.         x = ix; ix = ox; ox = x;
  900.         y = iy; iy = oy; oy = y;
  901.         z = iz; iz = oz; oz = z;
  902.       }
  903.  
  904.     /* check actually passes through the 3D graph volume */
  905.     if(iy > y_max3d && inrange(ix, x_min3d, x_max3d) && inrange(iz, min3d_z, max3d_z))
  906.       {
  907.         lx[0] = ix;
  908.         ly[0] = y_min3d;
  909.         lz[0] = iz;
  910.  
  911.         lx[1] = ix;
  912.         ly[1] = y_max3d;
  913.         lz[1] = iz;
  914.  
  915.         return(TRUE);
  916.       }
  917.     else {
  918.       return(FALSE);
  919.     }
  920.       }
  921.  
  922.     if(oz == -VERYLARGE || iz == -VERYLARGE)
  923.       {
  924.     if(iz == -VERYLARGE)
  925.       {
  926.         /* swap points so ix/iy/iz don't have a -VERYLARGE component */
  927.         x = ix; ix = ox; ox = x;
  928.         y = iy; iy = oy; oy = y;
  929.         z = iz; iz = oz; oz = z;
  930.       }
  931.  
  932.     /* check actually passes through the 3D graph volume */
  933.     if(iz > max3d_z && inrange(ix, x_min3d, x_max3d) && inrange(iy, y_min3d, y_max3d))
  934.       {
  935.         lx[0] = ix;
  936.         ly[0] = iy;
  937.         lz[0] = min3d_z;
  938.  
  939.         lx[1] = ix;
  940.         ly[1] = iy;
  941.         lz[1] = max3d_z;
  942.  
  943.         return(TRUE);
  944.       }
  945.     else {
  946.       return(FALSE);
  947.     }
  948.       }
  949.  
  950.     /*
  951.      * Quick outcode tests on the 3d graph volume
  952.      */
  953.  
  954.     /* 
  955.      * test z coord first --- most surface OUTRANGE points generated between
  956.      * min3d_z and z_min3d (i.e. when ticslevel is non-zero)
  957.      */
  958.     if(GPMAX(iz,oz) < min3d_z || GPMIN(iz,oz) > max3d_z)
  959.       return(FALSE);
  960.  
  961.     if(GPMAX(ix,ox) < x_min3d || GPMIN(ix,ox) > x_max3d)
  962.       return(FALSE);
  963.  
  964.     if(GPMAX(iy,oy) < y_min3d || GPMIN(iy,oy) > y_max3d)
  965.       return(FALSE);
  966.  
  967.     /*
  968.      * Special horizontal/vertical, etc. cases are checked and remaining
  969.      * slant lines are checked separately.
  970.      *
  971.      * The slant line intersections are solved using the parametric form
  972.      * of the equation for a line, since if we test x/y/z min/max planes explicitly
  973.      * then e.g. a  line passing through a corner point (x_min,y_min,z_min) 
  974.      * actually intersects all 3 planes and hence further tests would be required 
  975.      * to anticipate this and similar situations.
  976.      */
  977.  
  978.     /*
  979.      * Can have case (ix == ox && iy == oy && iz == oz) as both points OUTRANGE
  980.      */
  981.     if(ix == ox && iy == oy && iz == oz)
  982.       {
  983.     /* but as only define single outrange point, can't intersect 3D graph volume */
  984.     return(FALSE);
  985.       }
  986.  
  987.     if(ix == ox) {
  988.       if(iy == oy) {
  989.     /* line parallel to z axis */
  990.  
  991.     /* x and y coords must be in range, and line must span both min3d_z and max3d_z */
  992.     /* note that spanning min3d_z implies spanning max3d_z as both points OUTRANGE */
  993.     if(!inrange(ix, x_min3d, x_max3d) || !inrange(iy, y_min3d, y_max3d))
  994.       {
  995.         return(FALSE);
  996.       }
  997.  
  998.     if (inrange(min3d_z, iz, oz)) {
  999.       lx[0] = ix;
  1000.       ly[0] = iy;
  1001.       lz[0] = min3d_z;
  1002.  
  1003.       lx[1] = ix;
  1004.       ly[1] = iy;
  1005.       lz[1] = max3d_z;
  1006.  
  1007.       return(TRUE);
  1008.     } else
  1009.       return(FALSE);
  1010.       }
  1011.       
  1012.       if(iz == oz) {
  1013.     /* line parallel to y axis */
  1014.     
  1015.     /* x and z coords must be in range, and line must span both y_min3d and y_max3d */
  1016.     /* note that spanning y_min3d implies spanning y_max3d, as both points OUTRANGE */
  1017.     if(!inrange(ix, x_min3d, x_max3d) || !inrange(iz, min3d_z, max3d_z))
  1018.       {
  1019.         return(FALSE);
  1020.       }
  1021.  
  1022.     if (inrange(y_min3d, iy, oy)) {
  1023.       lx[0] = ix;
  1024.       ly[0] = y_min3d;
  1025.       lz[0] = iz;
  1026.  
  1027.       lx[1] = ix;
  1028.       ly[1] = y_max3d;
  1029.       lz[1] = iz;
  1030.  
  1031.       return(TRUE);
  1032.     } else
  1033.       return(FALSE);
  1034.       }
  1035.  
  1036.       /* nasty 2D slanted line in a yz plane */
  1037.       
  1038.       if(!inrange(ox, x_min3d, x_max3d))
  1039.     return(FALSE);
  1040.  
  1041.       t[0] = (y_min3d - iy)/(oy - iy);
  1042.       t[1] = (y_max3d - iy)/(oy - iy);
  1043.       
  1044.       if(t[0] > t[1]) {
  1045.     swap = t[0];t[0] = t[1];t[1] = swap;
  1046.       }
  1047.  
  1048.       t[2] = (min3d_z - iz)/(oz - iz);
  1049.       t[3] = (max3d_z - iz)/(oz - iz);
  1050.       
  1051.       if(t[2] > t[3]) {
  1052.     swap = t[2];t[2] = t[3];t[3] = swap;
  1053.       }
  1054.  
  1055.       t_min = GPMAX(GPMAX(t[0],t[2]),0.0);
  1056.       t_max = GPMIN(GPMIN(t[1],t[3]),1.0);
  1057.       
  1058.       if(t_min > t_max)
  1059.     return(FALSE);
  1060.  
  1061.       lx[0] = ix;
  1062.       ly[0] = iy + t_min * (oy - iy);
  1063.       lz[0] = iz + t_min * (oz - iz);
  1064.       
  1065.       lx[1] = ix;
  1066.       ly[1] = iy + t_max * (oy - iy);
  1067.       lz[1] = iz + t_max * (oz - iz);
  1068.       
  1069.       /*
  1070.        * Can only have 0 or 2 intersection points -- only need test one coord
  1071.        */
  1072.       if(inrange(ly[0], y_min3d, y_max3d) && 
  1073.      inrange(lz[0], min3d_z, max3d_z))
  1074.     {
  1075.       return(TRUE);
  1076.     }
  1077.       
  1078.       return(FALSE);
  1079.     }
  1080.       
  1081.     if(iy == oy) {
  1082.       /* already checked case (ix == ox && iy == oy) */
  1083.       if(oz ==  iz) {
  1084.     /* line parallel to x axis */
  1085.     
  1086.     /* y and z coords must be in range, and line must span both x_min3d and x_max3d */
  1087.     /* note that spanning x_min3d implies spanning x_max3d, as both points OUTRANGE */
  1088.     if(!inrange(iy, y_min3d, y_max3d) || !inrange(iz, min3d_z, max3d_z))
  1089.       {
  1090.         return(FALSE);
  1091.       }
  1092.  
  1093.     if (inrange(x_min3d, ix, ox)) {
  1094.       lx[0] = x_min3d;
  1095.       ly[0] = iy;
  1096.       lz[0] = iz;
  1097.  
  1098.       lx[1] = x_max3d;
  1099.       ly[1] = iy;
  1100.       lz[1] = iz;
  1101.  
  1102.       return(TRUE);
  1103.     } else
  1104.       return(FALSE);
  1105.       }
  1106.  
  1107.       /* nasty 2D slanted line in an xz plane */
  1108.  
  1109.       if(!inrange(oy, y_min3d, y_max3d))
  1110.     return(FALSE);
  1111.  
  1112.       t[0] = (x_min3d - ix)/(ox - ix);
  1113.       t[1] = (x_max3d - ix)/(ox - ix);
  1114.       
  1115.       if(t[0] > t[1]) {
  1116.     swap = t[0];t[0] = t[1];t[1] = swap;
  1117.       }
  1118.  
  1119.       t[2] = (min3d_z - iz)/(oz - iz);
  1120.       t[3] = (max3d_z - iz)/(oz - iz);
  1121.       
  1122.       if(t[2] > t[3]) {
  1123.     swap = t[2];t[2] = t[3];t[3] = swap;
  1124.       }
  1125.  
  1126.       t_min = GPMAX(GPMAX(t[0],t[2]),0.0);
  1127.       t_max = GPMIN(GPMIN(t[1],t[3]),1.0);
  1128.       
  1129.       if(t_min > t_max)
  1130.     return(FALSE);
  1131.  
  1132.       lx[0] = ix + t_min * (ox - ix);
  1133.       ly[0] = iy;
  1134.       lz[0] = iz + t_min * (oz - iz);
  1135.       
  1136.       lx[1] = ix + t_max * (ox - ix);
  1137.       ly[1] = iy;
  1138.       lz[1] = iz + t_max * (oz - iz);
  1139.       
  1140.       /*
  1141.        * Can only have 0 or 2 intersection points -- only need test one coord
  1142.        */
  1143.       if(inrange(lx[0], x_min3d, x_max3d) && 
  1144.      inrange(lz[0], min3d_z, max3d_z))
  1145.     {
  1146.       return(TRUE);
  1147.     }
  1148.       
  1149.       return(FALSE);
  1150.     }
  1151.     
  1152.     if(iz == oz) {
  1153.       /* already checked cases (ix == ox && iz == oz) and (iy == oy && iz == oz) */
  1154.  
  1155.       /* nasty 2D slanted line in an xy plane */
  1156.  
  1157.       if(!inrange(oz, min3d_z, max3d_z))
  1158.     return(FALSE);
  1159.  
  1160.       t[0] = (x_min3d - ix)/(ox - ix);
  1161.       t[1] = (x_max3d - ix)/(ox - ix);
  1162.       
  1163.       if(t[0] > t[1]) {
  1164.     swap = t[0];t[0] = t[1];t[1] = swap;
  1165.       }
  1166.  
  1167.       t[2] = (y_min3d - iy)/(oy - iy);
  1168.       t[3] = (y_max3d - iy)/(oy - iy);
  1169.       
  1170.       if(t[2] > t[3]) {
  1171.     swap = t[2];t[2] = t[3];t[3] = swap;
  1172.       }
  1173.  
  1174.       t_min = GPMAX(GPMAX(t[0],t[2]),0.0);
  1175.       t_max = GPMIN(GPMIN(t[1],t[3]),1.0);
  1176.       
  1177.       if(t_min > t_max)
  1178.     return(FALSE);
  1179.  
  1180.       lx[0] = ix + t_min * (ox - ix);
  1181.       ly[0] = iy + t_min * (oy - iy);
  1182.       lz[0] = iz;
  1183.       
  1184.       lx[1] = ix + t_max * (ox - ix);
  1185.       ly[1] = iy + t_max * (oy - iy);
  1186.       lz[1] = iz;
  1187.       
  1188.       /*
  1189.        * Can only have 0 or 2 intersection points -- only need test one coord
  1190.        */
  1191.       if(inrange(lx[0], x_min3d, x_max3d) && 
  1192.      inrange(ly[0], y_min3d, y_max3d))
  1193.     {
  1194.       return(TRUE);
  1195.     }
  1196.       
  1197.       return(FALSE);
  1198.     }
  1199.   
  1200.     /* really nasty general slanted 3D case */
  1201.  
  1202.     /*
  1203.       Solve parametric equation
  1204.  
  1205.       (ix, iy, iz) + t (diff_x, diff_y, diff_z)
  1206.  
  1207.       where 0.0 <= t <= 1.0 and
  1208.  
  1209.       diff_x = (ox - ix);
  1210.       diff_y = (oy - iy);
  1211.       diff_z = (oz - iz);
  1212.      */
  1213.  
  1214.     t[0] = (x_min3d - ix)/(ox - ix);
  1215.     t[1] = (x_max3d - ix)/(ox - ix);
  1216.  
  1217.     if(t[0] > t[1]) {
  1218.       swap = t[0];t[0] = t[1];t[1] = swap;
  1219.     }
  1220.  
  1221.     t[2] = (y_min3d - iy)/(oy - iy);
  1222.     t[3] = (y_max3d - iy)/(oy - iy);
  1223.     
  1224.     if(t[2] > t[3]) {
  1225.       swap = t[2];t[2] = t[3];t[3] = swap;
  1226.     }
  1227.     
  1228.     t[4] = (iz == oz) ? 0.0 : (min3d_z - iz)/(oz - iz);
  1229.     t[5] = (iz == oz) ? 1.0 : (max3d_z - iz)/(oz - iz);
  1230.     
  1231.     if(t[4] > t[5]) {
  1232.       swap = t[4];t[4] = t[5];t[5] = swap;
  1233.     }
  1234.  
  1235.     t_min = GPMAX(GPMAX(t[0],t[2]),GPMAX(t[4],0.0));
  1236.     t_max = GPMIN(GPMIN(t[1],t[3]),GPMIN(t[5],1.0));
  1237.  
  1238.     if(t_min > t_max)
  1239.       return(FALSE);
  1240.  
  1241.     lx[0] = ix + t_min * (ox - ix);
  1242.     ly[0] = iy + t_min * (oy - iy);
  1243.     lz[0] = iz + t_min * (oz - iz);
  1244.  
  1245.     lx[1] = ix + t_max * (ox - ix);
  1246.     ly[1] = iy + t_max * (oy - iy);
  1247.     lz[1] = iz + t_max * (oz - iz);
  1248.  
  1249.     /*
  1250.      * Can only have 0 or 2 intersection points -- only need test one coord
  1251.      */
  1252.     if(inrange(lx[0], x_min3d, x_max3d) && 
  1253.        inrange(ly[0], y_min3d, y_max3d) &&
  1254.        inrange(lz[0], min3d_z, max3d_z))
  1255.       {
  1256.     return(TRUE);
  1257.       }
  1258.     
  1259.     return(FALSE);
  1260.   }
  1261.